package com.leyou.item.service.impl;

import com.leyou.item.client.ItemClient;
import com.leyou.item.entity.Goods;
import com.leyou.item.entity.SearchList;
import com.leyou.item.repository.GoodsRepository;
import com.leyou.item.service.SearchGoodsService;
import com.leyou.starter.elastic.entity.PageInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.Nested;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SearchGoodsServiceImpl implements SearchGoodsService {
    @Autowired
    GoodsRepository goodsRepository;

    @Autowired
    ItemClient itemClient;

    @Override
    public Mono<List<String>> getSuggestion(String key) {

        return goodsRepository.suggestBySingleField("suggestion", key);
    }

    @Override
    public Mono<PageInfo<Goods>> getList(SearchList list) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //查询
        sourceBuilder.query(QueryBuilders.matchQuery("title", list.getKey()));
        //分页
        int size = 20;
        Integer page = list.getPage();
        sourceBuilder.from(size * (page - 1));
        sourceBuilder.size(size);

        //高亮
        sourceBuilder.highlighter(new HighlightBuilder()
                .field("title")
                .preTags("<am>")
                .postTags("</am>"));
        //排序
        Set<String> sortCondition = new HashSet<>();

        sortCondition.add("prices");
        sortCondition.add("sold");
        sortCondition.add("updateTime");
        String filed = list.getSortBy();
        if (StringUtils.isNotEmpty(filed) && sortCondition.contains(filed)) {

            sourceBuilder.sort(list.getSortBy(), list.getDesc() ? SortOrder.DESC : SortOrder.ASC);
        }

        //过滤

        return goodsRepository.queryBySourceBuilderForPageHighlight(sourceBuilder);


    }

    @Override
    public Mono<Map> getFilter(SearchList list) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchAllQuery());
        sourceBuilder.size(0);

        sourceBuilder.aggregation(AggregationBuilders.terms("categoryAggs").field("categoryId").size(30));
        sourceBuilder.aggregation(AggregationBuilders.terms("brandAggs").field("brandId").size(30));

        sourceBuilder.aggregation(AggregationBuilders.nested("specsAggs", "specs")
                .subAggregation(AggregationBuilders.terms("nameAggs").field("specs.name").size(30)
                        .subAggregation(AggregationBuilders.terms("valueAggs").field("specs.value").size(30))));


        Mono<Aggregations> aggregation = goodsRepository.aggregationBySourceBuilder(sourceBuilder);
        Mono<Map> mapMono = aggregation.map(aggregations -> {
            Map map = new TreeMap();

            Terms categoryAggs = aggregations.get("categoryAggs");
            List<Long> categoryIds = categoryAggs
                    .getBuckets()
                    .stream()
                    .map(bucket -> ((Terms.Bucket) bucket).getKeyAsNumber())
                    .map(Number::longValue)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(categoryIds)) {
                map.put("分类", itemClient.queryCategoryByIds(categoryIds));
            }

            Terms brandAggs = aggregations.get("brandAggs");
            List<Long> brandIds = brandAggs
                    .getBuckets()
                    .stream()
                    .map(bucket -> ((Terms.Bucket) bucket).getKeyAsNumber())
                    .map(Number::longValue)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(brandIds)) {
                map.put("品牌", itemClient.queryBrandByIds(brandIds));
            }

            Nested specsAggs = aggregations.get("specsAggs");
            Terms nameAggs = specsAggs.getAggregations().get("nameAggs");
            nameAggs
                    .getBuckets()
                    .stream()
                    .forEach(nameBucket -> {
                        ArrayList valueList = new ArrayList();
                        String name = (String) nameBucket.getKey();
                        Terms valueAggs = nameBucket.getAggregations().get("valueAggs");
                        valueAggs.getBuckets()
                                .forEach(valueBuckets -> {
                                    String value = (String) valueBuckets.getKey();
                                    valueList.add(value);
                                });
                        map.put(name, valueList);
                    });


            return map;
        });
        return mapMono;
    }
}
